// 工具类 js 
/* 
    求最大值的函数 传入任意个参数 找到其中最大的那一个值
*/
function maxNum() {
    var max = arguments[0]
    for (var i = 1; i < arguments.length; i++) {
        if (arguments[i] > max) {
            max = arguments[i]
        }
    }
    return max
}
/* 
    求最小值的函数 传入任意个参数 找到其中最小的那一个值
*/
function minNum() {
    var min = arguments[0]
    for (var i = 1; i < arguments.length; i++) {
        if (arguments[i] < min) {
            min = arguments[i]
        }
    }
    return min
}

/* 
    求范围随机数的函数
    @param a 范围之间较小的那个数
    @param b 范围之间较大的那个数
    @return  得到的一个范围之间的随机数
*/
function getRandom(a, b) {
    return Math.floor(Math.random() * (b - a + 1) + a)
}

/* 
    @param id 要获取的元素的 id
    @return 通过 id 获取到的元素
*/
function my$(id) {
    return document.getElementById(id)
}

/* 
    通过 id 或者 类名 或者 标签名获取元素
    @param selector 传入的选择器
    @param context  选择元素的范围 可选 如果没有传入就是 document
    @return  找到的元素/伪数组
*/
// function $(selector, context) {
//     context = context || document
//     if (selector.indexOf("#") == 0) {
//         return document.getElementById(selector.slice(1))
//     }
//     if (selector.indexOf(".") == 0) {
//         return context.getElementsByClassName(selector.slice(1))
//     }
//     return context.getElementsByTagName(selector)
// }

/* 
    @param ele 要设置或者获取属性的元素
    @param attr 要设置或者获取的属性
    @param value 可选参数  要设置的属性值
    @return 获取到的元素的某一个属性值
*/
function css(ele, attr, value) {
    if (typeof value === "undefined") {
        // 没有传入 value 这个参数 那么就是获取
        return window.getComputedStyle ? window.getComputedStyle(ele)[attr] : ele.currentStyle[attr]
    }
    ele.style[attr] = value
}
/* 
    光标到页面左右的距离
    @param e event对象
    @return {x:...,y:....}
*/
function page(e) {
    if (e.pageX) {
        return { x: e.pageX, y: e.pageY }
    }
    var _left = document.documentElement ? document.documentElement.scrollLeft + e.clientX : document.body.scrollLeft + e.clientX
    var _top = document.documentElement ? document.documentElement.scrollTop + e.clientY : document.body.scrollTop + e.clientY
    return {
        x: parseInt(_left),
        y: parseInt(_top)
    }
}

/* 
    获取元素的实际宽度
    @param ele  要获取的元素
    @return 获取到的宽度
*/
function outerW(ele) {
    var res = css(ele, "display")
    if (res === "none") {
        return parseFloat(css(ele, "width")) + parseFloat(css(ele, "paddingLeft")) + parseFloat(css(ele, "paddingRight")) + parseFloat(css(ele, "borderLeftWidth")) + parseFloat(css(ele, "borderRightWidth"))
    }
    return ele.offsetWidth
}
/* 
    获取元素的实际高度
    @param ele  要获取的元素
    @return 获取到的高度
*/
function outerW(ele) {
    var res = css(ele, "display")
    if (res === "none") {
        return parseFloat(css(ele, "height")) + parseFloat(css(ele, "paddingTop")) + parseFloat(css(ele, "paddingBottom")) + parseFloat(css(ele, "borderTopWidth")) + parseFloat(css(ele, "borderBottomWidth"))
    }
    return ele.offsetWidth
}
/* 
    获取元素的不包含边框的宽度
    @param ele  要获取的元素
    @return 获取到的宽度
*/
function innerW(ele) {
    var res = css(ele, "display")
    if (res === "none") {
        return parseFloat(css(ele, "width")) + parseFloat(css(ele, "paddingLeft")) + parseFloat(css(ele, "paddingRight"))
    }
    return ele.clientWidth
}
/* 
    获取元素的不包含边框的高度
    @param ele  要获取的元素
    @return 获取到的高度
*/
function innerH(ele) {
    var res = css(ele, "display")
    if (res === "none") {
        return parseFloat(css(ele, "height")) + parseFloat(css(ele, "paddingTop")) + parseFloat(css(ele, "paddingBottom"))
    }
    return ele.clientHeight
}

/* 
    添加事件监听
    @param ele 要添加事件监听的元素
    @param type  事件的类型
    @param fn 事件处理函数
*/

function on(ele, type, fn) {
    if (ele.addEventListener) {
        // 应该判断事件类型有没有 on
        if(type.indexOf("on") == 0){   
            type = type.slice(2)
        }
        ele.addEventListener(type, fn)
    } else {
        if (type.indexOf("on") !== 0) {
            type = "on" + type
        }
        ele.attachEvent(type, fn)
    }
}





const utils = {

  /* 

    @param ele 要执行运动的元素
    @param option 要设置的参数
    @param duration  运动持续的时间
    @param fn 运动执行完毕以后的回调函数
*/
  animate (ele, options, duration,fn) {
    clearInterval(ele.time)
    // 设置初始值 和运动区间
    let start = {}, range = {}
    for (var key in options) {
        start[key] = parseFloat(css(ele, key))
        range[key] = options[key] - start[key]
    }
    // 记录开始执行时候 的毫秒值
    let startTime = +new Date()
    ele.time = setInterval(() => {
        // 记录下当时的时间
        let nowTime = +new Date()
        // 求时间差值
        let timeDifference = Math.min(nowTime - startTime,duration)

        // 让元素动起来
        for (var attr in options) {
            // left = 单位时间运动的距离 * 运动时间 + 起始值
            // left = 运动距离 / 总的运动时间 * 已经运动的时间 + 起始值
            let result = range[attr] / duration * timeDifference + start[attr]
            ele.style[attr] =  attr == "opacity" ? result  : result + "px"
        }
        // 判断是否停止运动
        if (timeDifference === duration) {
            clearInterval(ele.time)
            fn && fn()
        }
    }, 10)
  },
  /* 
    让元素 淡出
    @param ele 要设置的元素
    @param duration 淡出的时间
    @param fn 回调函数 
*/
  fadeOut (ele,duration,fn) {
    ele.style.display = "block"
    ele.style.opacity = 1
    this.animate(ele,{"opacity":0},duration,() => {
        ele.style.display = "none"
        fn && fn()
    })
  },
/* 
  让元素 淡入
  @param ele 要设置的元素
  @param duration 淡入的时间
  @param fn 回调函数 
*/
  fadeIn (ele,duration,fn) {
    ele.style.display = "block"
    ele.style.opacity = 0
    this.animate(ele,{"opacity":1},duration,fn)
  },
/**
 * 获取cookie的方法
 * @param {string} key 要获取的cookie的名称
 * @return {string} 这条cookie的值，如果不存在返回undefined
 */
  getCookie (key) {
    const str = document.cookie
    const cookie = str.split('; ')
    // const obj = new Object()
    // cookie.forEach(item => {
    //   const arr = item.split('=')
    //   obj[arr[0]] = decodeURIComponent(arr[1])
    // })

    const obj = cookie.reduce((ob, item) => {
      const arr = item.split('=')
      ob[arr[0]] = decodeURIComponent(arr[1])
      return ob
    }, {})
    return obj[key]
  },
  /**
   * 设置cookie
   * @param {string} key 存cookie的名称
   * @param {string} value 存cookie的值
   * @param {object} [option] 可选参数 expires过期时间，path就是路径，比如 {expires: 7, path: '/'} 就是存一条7天后过期的根目录的cookie
   */
  setCookie (key, value, option) {
    let str = `${key}=${encodeURIComponent(value)}`
    // 如果option传了
    if (option) {
      // 再判断传了那些属性
      if (option.expires) {
        // 过期时间
        var date = new Date()
        date.setDate(date.getDate() + option.expires)
        str += `;expires=${date.toUTCString()}`
      }
      if (option.path) {
        // 路径
        str += `;path=${option.path}`
      }
    }
    document.cookie = str
  },
  /**
   * ajax get请求
   * @param {string} url 请求的地址
   * @param {object} query 请求所要携带的参数
   * @param {function} fn 请求数据返回之后的回调
   * @param {boolean}  [isJson] 请求的数据是否为json，默认为true
   */
  get (url, query, fn, isJson = true) {
    // 0. 准备工作：如果传了query，就要再url后面拼接query
    if (query) {
      url += '?'
      for (var key in query) {
        url += `${key}=${query[key]}&`
      }
      // 结束以后会多一个&
      url = url.slice(0, -1)
    }
    // 1. 创建核心对象
    var xhr = new XMLHttpRequest()
    // 2. open
    xhr.open('get', url)
    // 3. send
    xhr.send()
    // 4. 监听状态
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          // 请求成功
          // isJson为true就解析之后再传递，否则就传本身
          var respText = isJson ? JSON.parse(xhr.responseText) : xhr.responseText
          // 逻辑短路，fn有效才调用
          fn && fn(respText)
        }
      }
    }
  },
  /**
   * ajax post请求
   * @param {string} url 请求的地址
   * @param {object} query 请求所要携带的参数
   * @param {function} fn 请求数据返回之后的回调
   * @param {boolean}  [isJson] 请求的数据是否为json，默认为true
   */
  post (url, query, fn, isJson = true) {
    var str = ''
    if (query) {
      for (var key in query) {
        str += `${key}=${query[key]}&`
      }
      str = str.slice(0, -1)
    }
    var xhr = new XMLHttpRequest()
    xhr.open('post', url)
    // post请求数据还是按照urlencoded的方式发送
    xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded")
    xhr.send(str)
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          fn && fn(isJson ? JSON.parse(xhr.responseText) : xhr.responseText)
        }
      }
    }
  },
  /**
   * jsonp请求
   * @param {string} url 请求的地址
   * @param {string} cbName 回调函数名 
   * @param {object} [query] 其他要携带的参数
   */
  jsonp (url, cbName, query) {
    url += `?cb=${cbName}`
    if (query) {
      for (var key in query) {
        url += `&${key}=${query[key]}`
      }
    }
    var script = document.createElement('script')
    script.src = url
    document.body.appendChild(script)
    document.body.removeChild(script) // 过河拆桥
  },
  /**
   * 基于promise的get请求
   * @param {string} url 请求的地址
   * @param {object} query 请求所要携带的参数
   * @param {boolean}  [isJson] 请求的数据是否为json，默认为true
   */
  fetch (url, query, isJson = true) {
    if (query) {
      url += '?'
      for (var key in query) {
        url += `${key}=${query[key]}&`
      }
      // 结束以后会多一个&
      url = url.slice(0, -1)
    }
    return new Promise((resolve, reject) => {
      var xhr = new XMLHttpRequest()
      xhr.open('get', url)
      xhr.send()
      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
            resolve(isJson ? JSON.parse(xhr.responseText) : xhr.responseText)
          } else {
            reject()
          }
        }
      }
    })
  }
}

